package org.xmeta;

import org.xmeta.cache.ThingEntry;

import java.util.Map;

public class ThingActionListenerProvider implements ActionListenerProvider{
    ThingEntry thingEntry;

    public ThingActionListenerProvider(Thing thing) {
        this.thingEntry = new ThingEntry(thing);
    }

    public Thing getThing() {
        return thingEntry.getThing();
    }

    @Override
    public ActionListener createActionListener(ActionContext actionContext) {
        if (actionContext.isDisableGlobalContext()) {
            return null;
        }

        Thing thing = thingEntry.getThing();
        if (thing != null) {
            return new ThingActionListener(thing, actionContext);
        } else {
            return null;
        }
    }

    static class ThingActionListener implements ActionListener {
        ActionContext actionContext;
        Thing thing;

        public ThingActionListener(Thing thing, ActionContext actionContext) {
            this.thing = thing;
            this.actionContext = actionContext;
        }

        @Override
        public void onInit(Action action, Object caller, ActionContext actionContext, Map<String, Object> params, ActionListenerExecutor executor) {
            boolean doDisableContext = false;
            if (!actionContext.peek().disableGlobalContext) {
                actionContext.peek().disableGlobalContext = true;
                doDisableContext = true;
            }

            try {
                thing.doAction("onInit", this.actionContext, "action", action, "caller", caller, "acContext",
                        actionContext, "params", params, "executor", executor);
            } finally {
                if (doDisableContext) {
                    actionContext.peek().disableGlobalContext = false;
                }
            }
        }

        @Override
        public void onSuccess(Action action, Object caller, ActionContext actionContext, Object result, ActionListenerExecutor executor) {
            boolean doDisableContext = false;
            if (!actionContext.peek().disableGlobalContext) {
                actionContext.peek().disableGlobalContext = true;
                doDisableContext = true;
            }

            try {
                thing.doAction("onSuccess", this.actionContext, "action", action, "caller", caller, "acContext",
                        actionContext, "result", result, "executor", executor);
            } finally {
                if (doDisableContext) {
                    actionContext.peek().disableGlobalContext = false;
                }
            }
        }

        @Override
        public void onException(Action action, Object caller, ActionContext actionContext, Throwable t, ActionListenerExecutor executor) {
            boolean doDisableContext = false;
            if (!actionContext.peek().disableGlobalContext) {
                actionContext.peek().disableGlobalContext = true;
                doDisableContext = true;
            }

            try {
                thing.doAction("onException", this.actionContext, "action", action, "caller", caller, "acContext",
                        actionContext, "exception", t, "executor", executor);
            } finally {
                if (doDisableContext) {
                    actionContext.peek().disableGlobalContext = false;
                }
            }
        }

        @Override
        public void onDoAction(Thing thing, String actionName, Action action, ActionContext actionContext, Map<String, Object> params, ActionListenerExecutor executor) {
            boolean doDisableContext = false;
            if (!actionContext.peek().disableGlobalContext) {
                actionContext.peek().disableGlobalContext = true;
                doDisableContext = true;
            }

            try {
                thing.doAction("onDoAction", this.actionContext, "action", action, "actionName", actionName, "acContext",
                        actionContext, "thing", thing, "executor", executor);
            } finally {
                if (doDisableContext) {
                    actionContext.peek().disableGlobalContext = false;
                }
            }
        }

        @Override
        public void onDoActionFinished(Thing thing, String actionName, Action action, ActionContext actionContext, Map<String, Object> params, ActionListenerExecutor executor, Object result) throws Exception {
            boolean doDisableContext = false;
            if (!actionContext.peek().disableGlobalContext) {
                actionContext.peek().disableGlobalContext = true;
                doDisableContext = true;
            }

            try {
                thing.doAction("onDoActionFinished", this.actionContext, "action", action, "actionName", actionName, "acContext",
                        actionContext, "thing", thing, "executor", executor, "result", result);
            } finally {
                if (doDisableContext) {
                    actionContext.peek().disableGlobalContext = false;
                }
            }
        }

        @Override
        public String getName() {
            return thing.getMetadata().getPath();
        }
    }
}
